﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Data;
using System.Xml;
using System.Threading;
using System.Data.SqlClient;
using System.IO;
using System.Xml.Serialization;
using System.Globalization;
using Microsoft.Win32;
using System.Collections;


namespace eOfficeDevManager
{
    public interface IDataInterface
    {
        bool Init(DeviceHandler devInfo);
        DataSet DownLoadData(DataSet columnHeadings);
        bool DeleteLog(DataSet logToDelete);
        DataSet DownLoadUserData(bool newOnly);

        event EventHandler UpdateDeviceStatus;
        event EventHandler CollectLogEvent;

        bool IsEventSupported();
    }
    public enum DeviceStatus
    {
        Running,
        Stopped,
        Failed
    }
    public enum DownloadStatus
    {
        DeviceStarted,
        Fetching,
        NoRecords,
        Downloaded,
        Failed
    }
    public class DownloadEventArg : EventArgs
    {
        DownloadStatus _downloadStatus;

        public DownloadStatus DownloadStatus
        {
            get { return _downloadStatus; }
            set { _downloadStatus = value; }
        }
        string _message;

        public string Message
        {
            get { return _message; }
            set { _message = value; }
        }
    }
    /// <summary>
    /// This class wraps the device specific interfaces and starts the thread for downloading from
    /// the device.
    /// </summary>
    public class DeviceHandler
    {
        LogWriter _LogWrite = new LogWriter();
        public event EventHandler DownLoadStatus;
        #region deviceProperties

        public bool _dLog;

        public bool DLog
        {
            get { return _dLog; }
            set { _dLog = value; }
        }
        string _deviceID;
        public string DeviceID
        {
            set { _deviceID = value; }
            get { return _deviceID; }
        }
        string _deviceName;
        public string DeviceName
        {
            set { _deviceName = value; }
            get { return _deviceName; }
        }
        Thread _deviceThread;
        public Thread DeviceThread
        {
            set { _deviceThread = value; }
            get { return _deviceThread; }
        }
        Thread _eOfficeThread;

        public Thread EOfficeThread
        {
            get { return _eOfficeThread; }
            set { _eOfficeThread = value; }
        }

        DeviceStatus _status;
        public DeviceStatus DeviceStatus
        {
            set { _status = value; }
            get { return _status; }
        }
        string _driverPath;
        public string DriverPath
        {
            set { _driverPath = value; }
            get { return _driverPath; }
        }

        string _connectString;
        public string ConnectionString
        {
            set { _connectString = value; }
            get { return _connectString; }
        }
        private Dictionary<string, string> _xmlDictionary;

        public Dictionary<string, string> XmlDictionary
        {
            get { return _xmlDictionary; }
            set { _xmlDictionary = value; }
        }

        #endregion deviceProperties

        #region device thread and related functionalities
        public void StartDevice()
        {
            _deviceThread = new Thread(new ThreadStart(DeviceServiceThread));
            _deviceThread.Start();
        }

        public void StopService()
        {
            _deviceThread.Interrupt();
            _deviceThread.Abort();

        }
        IDataInterface _dataInterface;
        bool CollectInterface()
        {
            try
            {
                Assembly asmbly = Assembly.LoadFrom(DriverPath);
                _LogWrite.WriteToFile("Load File " + DriverPath);
                foreach (Type type in asmbly.GetTypes())
                {
                    if (type.IsClass == true)
                    {
                        if (type.GetInterface("IDataInterface") != null)
                        {
                            _dataInterface = (IDataInterface)asmbly.CreateInstance(type.ToString());
                            return true;
                        }
                    }
                    //if (typeof(IDataInterface).IsAssignableFrom(type))
                    //{
                    //    IDataInterface instance = (IDataInterface)Activator.CreateInstance(type);
                    //    instance.DownLoadData();
                    //}                   
                }
                return false;
            }
            catch (Exception exp)
            {
                //Danya all errors to be logged in to a file
                _LogWrite.LogTimePrefix = true;
                _LogWrite.WriteToFile(LogWriter.LogType.Error, exp.ToString());
                return false;
            }
        }

        private void DeviceServiceThread()
        {
            try
            {
                if (!CollectInterface()) return;
                DownloadEventArg eventArg = new DownloadEventArg();
                Console.WriteLine("Thread starts..");
                _LogWrite.LogTimePrefix = true;
                _LogWrite.WriteToFile("Thread Starts..");
                //eventArg.DownloadStatus = DownloadStatus.DeviceStarted;
                //eventArg.Message = "Initializing device";
                //DownLoadStatus(this, eventArg);
                _dataInterface.Init(this);
                // DataSet attendanceData = new DataSet();

                while (true)
                {
                    //Fill dataset with column names and need to pass that to
                    //the inteface function. Interface function inturn returns with the data 
                    DataSet attendanceData = new DataSet();
                    DataTable dTable = new DataTable();
                    DataColumn dCol1 = new DataColumn("Id", System.Type.GetType("System.Int32"));
                    DataColumn dCol2 = new DataColumn("DateTime", System.Type.GetType("System.DateTime"));
                    DataColumn dCol3 = new DataColumn("In/Out", System.Type.GetType("System.Int32"));
                    DataColumn dCol4 = new DataColumn("Status", System.Type.GetType("System.Int32"));
                    dTable.Columns.Add(dCol1);
                    dTable.Columns.Add(dCol2);
                    dTable.Columns.Add(dCol3);
                    dTable.Columns.Add(dCol4);
                    attendanceData.Tables.Add(dTable);
                    eventArg.DownloadStatus = DownloadStatus.Fetching;
                    eventArg.Message = "Trying to fetch record from device";
                    _LogWrite.WriteToFile("Dataset initialized");
                    DownLoadStatus(this, eventArg);
                  
                    attendanceData = _dataInterface.DownLoadData(attendanceData);
                    if (attendanceData.Tables[0].Rows.Count == 0) 
                    { 
                      _LogWrite.WriteToFile("Logs not available in device");
                      Thread.Sleep(5000);                   
                      continue;
                    }
                    _LogWrite.WriteToFile("One record collected from device");
                    //collect the data from the dataset and fills that in to the
                    //database. Pass the same dataset back to DeleteLog for deletion
                    foreach (DataRow theRow in attendanceData.Tables[0].Rows)
                    {
                        FillConnectionStr();
                        string _empID = ChooseEmpID(theRow["Id"].ToString());
                        if (_empID == null)
                        {
                            _LogWrite.WriteToFile("No employee enrolled");
                            eventArg.DownloadStatus = DownloadStatus.NoRecords;
                            eventArg.Message = "No Records Found";
                            DownLoadStatus(this, eventArg);
                            _LogWrite.WriteToFile("Empoyee not found in database");
                            continue;
                        }
                        string downLoadedData = "Downloded data for EmployID: " + _empID.ToString() + " on " + theRow["DateTime"].ToString();
                        eventArg.Message = downLoadedData;
                        _LogWrite.WriteToFile(downLoadedData);
                        DownLoadStatus(this, eventArg);

                        SqlConnection sqlcon = new SqlConnection(_connectString);
                        SqlCommand sqlcmd = new SqlCommand();
                        sqlcmd.Connection = sqlcon;
                        sqlcmd.CommandType = CommandType.StoredProcedure;
                        sqlcmd.CommandText = "DeviceLog";
                        sqlcmd.Parameters.AddWithValue("@date", (Convert.ToDateTime(theRow["DateTime"].ToString()).ToString("MM/dd/yyyy HH:mm:ss")));
                        sqlcmd.Parameters.AddWithValue("@inOut", theRow["In/Out"]);
                        sqlcmd.Parameters.AddWithValue("@Userid", _empID);
                        sqlcmd.Parameters.AddWithValue("@status", theRow["Status"]);
                        sqlcon.Open();
                        sqlcmd.ExecuteNonQuery();
                        sqlcon.Close();
                        _LogWrite.WriteToFile("Log Inserted to database");
                        _LogWrite.WriteToFile(LogWriter.LogType.Info, "Log id : " + _empID);
                        if (_dLog)
                        {
                            _dataInterface.DeleteLog(attendanceData);
                            _LogWrite.WriteToFile("Log deleted from device");
                        }
                        
                    }                    


                }
            }
            catch (Exception exp)
            {
                DownloadEventArg ev = new DownloadEventArg();
                ev.DownloadStatus = DownloadStatus.Failed;
                ev.Message = exp.Message;
                _LogWrite.LogTimePrefix = true;
                _LogWrite.WriteToFile(LogWriter.LogType.Error, "Download thread failed:" + exp.Message);

            }
        }
               

        private string ChooseEmpID(string _userId)
        {

            SqlConnection sqlcon = new SqlConnection(_connectString);
            SqlCommand sqlcmd = new SqlCommand();
            SqlDataReader sqldr;
            sqlcmd.Connection = sqlcon;
            sqlcmd.CommandText = "select EmpID from DevEmpDetails where CardID = '" + _userId + "'";
            sqlcon.Open();
            sqldr = sqlcmd.ExecuteReader();
            if (sqldr.Read())
                _userId = sqldr[0].ToString();
            else
                return null;
            sqldr.Close();
            sqlcon.Close();
            return _userId;

        }


        private void FillConnectionStr()
        {
            //XmlDocument settingsFile = new XmlDocument();
            //settingsFile.Load("config.xml");
            //XmlNode rootNode = settingsFile.DocumentElement;
            //XmlNodeList connectionList = rootNode.SelectNodes("/eOffice/ConnectionInfo");
            //for (int i = 0; i < connectionList.Count; ++i)
            //{
            //    XmlNode constr = connectionList[i].SelectSingleNode("descendant::settings");
            //    ConnectionString = constr.InnerText;
            //}
            try
            {
                RegistryKey regKey = Registry.CurrentUser.OpenSubKey("SOFTWARE\\eBird\\eOffice1.0");
                if (regKey != null)
                {
                    ConnectionString = regKey.GetValue("ConctString").ToString();
                }
            }
            catch (Exception exp)
            {
                _LogWrite.WriteToFile("Registry read failed" + exp.Message);
                //ConnectionString = "Data Source=(local);Initial Catalog=eOffice;User ID=sa;Password=bmjobmjo";
            }
            //ConnectionString = "Data Source=FILESERVER;Initial Catalog=eOffice;User ID=sa;Password=";

            _LogWrite.WriteToFile("Connection String: " + ConnectionString);
        }

        #endregion device thread and related functionalities
    }
    public class eOfficeDevManager
    {
        #region variables
        LogWriter _LogWrite = new LogWriter();
        System.Collections.ArrayList _activeDevices = new ArrayList();
        public event EventHandler DownloadStatusEvent;
        #endregion
       


        /// <summary>
        /// This is the function called to start the whole functionality.
        /// It loads the XML file and start one thread for each device.
        /// it keeps a collection of classes containing status and other information about the 
        /// devices. see flow chart
        /// </summary>
        /// <returns></returns>
        /// 
       

        public bool StartService()
        {
            _LogWrite.LogTimePrefix = true;
            //LogWrite("Start Device");
            _LogWrite.WriteToFile("Start Device");
            XmlDocument settingsFile = new XmlDocument();
            _LogWrite.WriteToFile("Loading Xml");
            settingsFile.Load("config.xml");
            XmlNode rootNode = settingsFile.DocumentElement;
            XmlNodeList deviceList = rootNode.SelectNodes("/eOffice/InstalledDevices/device");
            LogWrite("Starting enabled devices:" + deviceList.Count.ToString());
            for (int i = 0; i < deviceList.Count; ++i)
            {
                _LogWrite.WriteToFile("Current device:" + deviceList[i].Attributes["Name"].Value);
                if (deviceList[i].Attributes["Enabled"] == null)
                {
                    _LogWrite.WriteToFile("Device not enabled:" + deviceList[i].Attributes["Name"].Value);
                    continue;  
                }
                if (deviceList[i].Attributes["Enabled"].Value.ToLower() == "yes")
                { 
                    _LogWrite.WriteToFile("Starting enabled device:" + deviceList[i].Attributes["Name"].Value);
                    DeviceHandler devInfo = new DeviceHandler();
                    devInfo.DeviceID = deviceList[i].Attributes["ID"].Value;
                    devInfo.DeviceName = deviceList[i].Attributes["Name"].Value;
                    XmlNode driverPath = deviceList[i].SelectSingleNode("descendant::DriverPath");
                    devInfo.DriverPath = driverPath.InnerText;
                    devInfo.XmlDictionary = new Dictionary<string, string>();
                    foreach (XmlNode node in deviceList[i].ChildNodes)
                    {
                        devInfo.XmlDictionary.Add(node.Name, node.InnerText);
                    }
                    devInfo.DownLoadStatus += new EventHandler(devInfo_DownLoadStatus);
                    devInfo.StartDevice();
                    DownloadEventArg downloadEvent = new DownloadEventArg();
                    downloadEvent.DownloadStatus = DownloadStatus.DeviceStarted;
                    downloadEvent.Message = "Starting device :" + devInfo.DeviceName;
                    DownloadStatusEvent(this, downloadEvent);
                    _activeDevices.Add(devInfo);
                }
            }
            return true;
        }
        void devInfo_DownLoadStatus(object sender, EventArgs e)
        {
            DownloadStatusEvent(this, e);
        }
        public void LogWrite(string Log)
        {
            try
            {
                string strFileName = "LogFile.txt";
                StreamWriter sWriter = new StreamWriter(strFileName, true);
                DateTime dateTime = DateTime.Now;
                sWriter.WriteLine(dateTime + "\r\t" + Log + "\r\n");
                sWriter.Close();
                sWriter.Dispose();
            }
            catch (Exception exp)
            {
                //nothing to do proceed.
           }
        }
        

        /// <summary>
        /// Stop all device threads and kill the threads
        /// </summary>
        /// <returns></returns>   
        public bool StopService()
        {

            //DeviceHandler devInfo=new DeviceHandler();
            //if (Thread.CurrentThread.ThreadState == ThreadState.Running)
            //    Thread.CurrentThread.Abort();
            //if (devInfo.DeviceThread.IsAlive)
            //    devInfo.DeviceThread.Abort();
            //if (devInfo.DeviceStatus == DeviceStatus.Running)
            //    devInfo.DeviceStatus = DeviceStatus.Stopped;
            foreach (object obj in _activeDevices)
            {
                DeviceHandler devInfo = (DeviceHandler)obj;
                devInfo.StopService();
                devInfo = null;
            }
            _activeDevices.Clear();
            return true;
        }
        /// <summary>
        /// Returns a collection of classes created by the start service which contains the
        /// status of each device
        /// </summary>
        /// <returns></returns>
        void GetDeviceStatus()
        {
            return;
        }
        /// <summary>
        /// stops a particular device
        /// </summary>
        /// <param name="deviceID"></param>
        /// <returns></returns>
        bool StopDevice(int deviceID)
        {
            return true;
        }
        bool StopDevice(string deviceName)
        {
            return true;
        }
    }
}
